{
 "cells": [
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {},
   "outputs": [],
   "source": [
    "\n",
    "import json\n",
    "import pickle\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 46,
   "metadata": {},
   "outputs": [],
   "source": [
    "class Node:\n",
    "    buttom = []\n",
    "    above = []\n",
    "    arg = {}\n",
    "    ret = {}\n",
    "    base = 'Node'\n",
    "    option = {'buttom': buttom,\n",
    "              'above': above}\n",
    "\n",
    "    def __init__(self, name):\n",
    "        self.name = name\n",
    "\n",
    "    def __eq__(self, obj):\n",
    "        try:\n",
    "            result = (obj.base == self.base)\n",
    "        except:\n",
    "            return False\n",
    "        return True\n",
    "\n",
    "    def excute(self):\n",
    "        pass\n",
    "\n",
    "    def add_buttom(self, node):\n",
    "        self.buttom.append(node)\n",
    "\n",
    "    def add_above(self, node):\n",
    "        self.above.append(node)\n",
    "\n",
    "\n",
    "class Model(Node):\n",
    "    buttom = []\n",
    "    above = []\n",
    "    arg = {'data': None}\n",
    "    ret = {'return': None}\n",
    "\n",
    "    def excute(self):\n",
    "        print('run:', self.name)\n",
    "        for node in self.above:\n",
    "            print(node.name)\n",
    "            node.excute()\n",
    "\n",
    "\n",
    "class Load(Node):\n",
    "    buttom = []\n",
    "    above = []\n",
    "    arg = {'data': 1}\n",
    "    ret = {'clean': None}\n",
    "\n",
    "    def excute(self):\n",
    "        print('run:', self.name)\n",
    "        for node in self.above:\n",
    "            print(self.name)\n",
    "            node.excute()\n",
    "\n",
    "\n",
    "class Out(Node):\n",
    "    buttom = []\n",
    "    above = []\n",
    "    arg = {'data': None}\n",
    "    ret = {'return': None}\n",
    "\n",
    "    def excute(self):\n",
    "        print('run:', self.name)\n",
    "        for node in self.above:\n",
    "            print(node.name)\n",
    "            node.excute()\n",
    "\n",
    "\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 212,
   "metadata": {},
   "outputs": [],
   "source": [
    "struct = '''\n",
    "{\n",
    "\t\"rule_name\": \"base_rule\",\n",
    "\t\"struct\": [{\n",
    "\t\t\t\"name\": \"root\",\n",
    "\t\t\t\"type\": \"Load\",\n",
    "\t\t\t\"buttom\": [\"m_2_1\",\"m_2_2\"],\n",
    "\t\t\t\"above\": []\n",
    "\t\t},\n",
    "\t\t{\n",
    "\t\t\t\"name\": \"m_2_1\",\n",
    "\t\t\t\"type\": \"Model\",\n",
    "\t\t\t\"buttom\": [\"m_3\"],\n",
    "\t\t\t\"above\": [\"root\"]\n",
    "\t\t},\n",
    "        {\n",
    "\t\t\t\"name\": \"m_2_2\",\n",
    "\t\t\t\"type\": \"Model\",\n",
    "\t\t\t\"buttom\": [\"m_3\"],\n",
    "\t\t\t\"above\": [\"root\"]\n",
    "\t\t},\n",
    "\t\t{\n",
    "\t\t\t\"name\": \"m_3\",\n",
    "\t\t\t\"type\": \"Model\",\n",
    "\t\t\t\"buttom\": [\"o_4\"],\n",
    "\t\t\t\"above\": [\"m_2_1\",\"m_2_2\"]\n",
    "\t\t},\n",
    "\t\t{\n",
    "\t\t\t\"name\": \"o_4\",\n",
    "\t\t\t\"type\": \"Out\",\n",
    "\t\t\t\"buttom\": [],\n",
    "\t\t\t\"above\": [\"m_3\"]\n",
    "\t\t}\n",
    "\t]\n",
    "}\n",
    "'''\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 242,
   "metadata": {},
   "outputs": [],
   "source": [
    "class ModelBuilder:\n",
    "    def __init__(self):\n",
    "        self.rule = None\n",
    "        self.root = None\n",
    "        self.struct = None\n",
    "\n",
    "    def loads(self, jsond):\n",
    "        self.rule = json.loads(jsond)\n",
    "        self.root = self.rule['struct'][0]\n",
    "        self.struct = self.rule['struct']\n",
    "\n",
    "    def build(self):\n",
    "        if self.rule != None:\n",
    "            check = (self.root['name'] == 'root')\n",
    "            node_name = {}\n",
    "            for node in self.struct:\n",
    "                node_name[node['name']] = -1\n",
    "            for node in self.struct:\n",
    "                node_name[node['name']] += 1\n",
    "            check &= (sum([node_name[x] for x in node_name]) == 0)\n",
    "            if not check:\n",
    "                raise Exception(\"结构语法错误\")\n",
    "            else:\n",
    "                self._build(self.root)\n",
    "            build_result = []\n",
    "            for node in self.struct:\n",
    "                if len(node['buttom']) == 0:\n",
    "                    build_result.append(node)\n",
    "            return self.struct\n",
    "#             return build_result\n",
    "        else:\n",
    "            raise Exception('语法结构错误')\n",
    "\n",
    "    def find_node(self, node_name):\n",
    "        rnode=None\n",
    "        for index, node in enumerate(self.struct):\n",
    "            if self.struct[index]['name'] == node_name:\n",
    "                rnode=node\n",
    "                return rnode\n",
    "        if rnode==None:\n",
    "            raise Exception(\"未知的节点\")\n",
    "\n",
    "    def _build(self, node):\n",
    "        if node==None:\n",
    "            print(node)\n",
    "        node['compiled']=False\n",
    "        node['compile'] = globals()[node['type']]\n",
    "        for child_name in node['buttom']:\n",
    "            child = self.find_node(child_name)\n",
    "            self._build(child)\n",
    "        \n",
    "    def compile(self):\n",
    "        self._compile(self.root, None)\n",
    "        return self.struct\n",
    "\n",
    "    def _compile(self, node, father):\n",
    "        \n",
    "        if node['compiled']==False:\n",
    "            node['compile'] = node['compile'](node['name'])\n",
    "            print(node['compile'])\n",
    "        node['compiled']=True\n",
    "        for child_name in node['buttom']:\n",
    "            child = self.find_node(child_name)\n",
    "            self._compile(child, node)\n",
    "    def exec(self):\n",
    "        back = []     #函数返回的数据\n",
    "        curLevel = [[root]]    #当前遍历树的层级，双层列表\n",
    "        while curLevel:\n",
    "            temp = []        #遍历当前层级时存放的临时结点值\n",
    "            nextLevel = []      #下一层树结点\n",
    "            for i in curLevel:    \n",
    "                for j in i:      #注意，层级节点存放为双层列表\n",
    "                    temp.append(j.val)\n",
    "                    if j.children:    #当前结点是否存在子结点\n",
    "                        nextLevel.append(j.children)\n",
    "            back.append(temp)\n",
    "            curLevel = nextLevel\n",
    "        return back\n",
    "    \n",
    "\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 243,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "<__main__.Load object at 0x000002016D59E7B8>\n",
      "<__main__.Model object at 0x000002016D59E780>\n",
      "<__main__.Model object at 0x000002016D59EE10>\n",
      "<__main__.Out object at 0x000002016D59EEB8>\n",
      "<__main__.Model object at 0x000002016D59ED30>\n"
     ]
    },
    {
     "data": {
      "text/plain": [
       "[{'name': 'root',\n",
       "  'type': 'Load',\n",
       "  'buttom': ['m_2_1', 'm_2_2'],\n",
       "  'above': [],\n",
       "  'compiled': True,\n",
       "  'compile': <__main__.Load at 0x2016d59e7b8>},\n",
       " {'name': 'm_2_1',\n",
       "  'type': 'Model',\n",
       "  'buttom': ['m_3'],\n",
       "  'above': ['root'],\n",
       "  'compiled': True,\n",
       "  'compile': <__main__.Model at 0x2016d59e780>},\n",
       " {'name': 'm_2_2',\n",
       "  'type': 'Model',\n",
       "  'buttom': ['m_3'],\n",
       "  'above': ['root'],\n",
       "  'compiled': True,\n",
       "  'compile': <__main__.Model at 0x2016d59ed30>},\n",
       " {'name': 'm_3',\n",
       "  'type': 'Model',\n",
       "  'buttom': ['o_4'],\n",
       "  'above': ['m_2_1', 'm_2_2'],\n",
       "  'compiled': True,\n",
       "  'compile': <__main__.Model at 0x2016d59ee10>},\n",
       " {'name': 'o_4',\n",
       "  'type': 'Out',\n",
       "  'buttom': [],\n",
       "  'above': ['m_3'],\n",
       "  'compiled': True,\n",
       "  'compile': <__main__.Out at 0x2016d59eeb8>}]"
      ]
     },
     "execution_count": 243,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "builder = ModelBuilder()\n",
    "builder.loads(struct)\n",
    "builder.build()\n",
    "builder.compile()\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 237,
   "metadata": {
    "scrolled": false
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "<class '__main__.Model'>\n",
      "<class '__main__.Model'>\n",
      "<class '__main__.Out'>\n",
      "<class '__main__.Model'>\n",
      "<__main__.Model object at 0x000002016E9F13C8>\n",
      "<__main__.Out object at 0x000002016F0A40B8>\n"
     ]
    },
    {
     "data": {
      "text/plain": [
       "[{'name': 'root',\n",
       "  'type': 'Load',\n",
       "  'buttom': ['m_2_1', 'm_2_2'],\n",
       "  'above': [],\n",
       "  'compiled': True,\n",
       "  'compile': <__main__.Load at 0x2016e9f1b38>,\n",
       "  'p_above': []},\n",
       " {'name': 'm_2_1',\n",
       "  'type': 'Model',\n",
       "  'buttom': ['m_3'],\n",
       "  'above': ['root'],\n",
       "  'compiled': True,\n",
       "  'compile': <__main__.Model at 0x2016e9f1160>,\n",
       "  'p_above': [<__main__.Load at 0x2016e9f1b38>]},\n",
       " {'name': 'm_2_2',\n",
       "  'type': 'Model',\n",
       "  'buttom': ['m_3'],\n",
       "  'above': ['root'],\n",
       "  'compiled': True,\n",
       "  'compile': <__main__.Model at 0x2016f0a4358>,\n",
       "  'p_above': [<__main__.Load at 0x2016e9f1b38>]},\n",
       " {'name': 'm_3',\n",
       "  'type': 'Model',\n",
       "  'buttom': ['o_4'],\n",
       "  'above': ['m_2_1', 'm_2_2'],\n",
       "  'compiled': True,\n",
       "  'compile': <__main__.Model at 0x2016e9f13c8>,\n",
       "  'p_above': [<__main__.Model at 0x2016f0a4358>]},\n",
       " {'name': 'o_4',\n",
       "  'type': 'Out',\n",
       "  'buttom': [],\n",
       "  'above': ['m_3'],\n",
       "  'compiled': True,\n",
       "  'compile': <__main__.Out at 0x2016f0a40b8>,\n",
       "  'p_above': [<__main__.Model at 0x2016e9f13c8>]}]"
      ]
     },
     "execution_count": 237,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": []
  },
  {
   "cell_type": "code",
   "execution_count": 207,
   "metadata": {},
   "outputs": [],
   "source": [
    "def p(*args):\n",
    "    print(args)\n",
    "def p1(**args):\n",
    "    print(args)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 170,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "(1, 2, 3, 4)\n"
     ]
    }
   ],
   "source": [
    "p(1,2,3,4)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 172,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "({'1': 1, '2': 2},)\n"
     ]
    }
   ],
   "source": [
    "p({'1':1,'2':2})"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 11,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "run: Out\n",
      "Model\n",
      "run: Model\n",
      "Load\n",
      "run: Load\n",
      "Load\n",
      "run: Load\n"
     ]
    }
   ],
   "source": [
    "\n",
    "var_ = locals()\n",
    "model_map = dict()\n",
    "\n",
    "builder = ModelBuilder()\n",
    "builder.loads(struct)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "\n",
    "\"\"\"\n",
    "load_data=Load('load_data')\n",
    "decision=Model('decision')\n",
    "output=Out('output')\n",
    "load_data.add_buttom(decision)\n",
    "decision.add_above(load_data)\n",
    "decision.add_buttom(output)\n",
    "output.add_above(decision)\n",
    "print(load_data==output)\n",
    "\n",
    "#output.excute()\n",
    "serialize=pickle.dumps(output)\n",
    "print(serialize)\n",
    "rule=pickle.loads(serialize)\n",
    "rule.excute()\n",
    "\"\"\""
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.6.8"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 2
}
